﻿#region File Description
/*-----------------------------------------------------------------------------
 * Class: 
 *
 * Description...
 *
 *
 * Notes: Other relevant information goes here.
 -------------------------------------------------------------------------------*/
#endregion

namespace Cubezicles
{
    using System.Collections.Generic;
    using System.Linq;
    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Graphics;
    using Microsoft.Xna.Framework.Input;

    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        public Dictionary<string, string> Messages { get; private set; }

        // Current state of the game
        public enum GameState { Loading, Running, Won, Lost }
        GameState currentGameState = GameState.Loading;

        private GraphicsDeviceManager graphics;

        public SpriteBatch SpriteBatch { get; private set; }

        public Dictionary<string, SpriteFont> Fonts { get; private set; }

        // Dot texture that I happen to use a lot surprisingly
        public Texture2D dot;

        // Non-ugly splash screen + winning screen image
        public Texture2D splashScreen;
        public Texture2D winScreen;

        // Interface blue color
        public Color UIblue = new Color(75, 105, 125);

        // Current Camera (so that the interface can handle the camera.....)
        public Camera CurrentCam { get; private set; }

        // Current Time
        public Clock time { get; private set; }

        // Mouse States
        public MouseState oldms, ms;

        // Keyboard States
        public KeyboardState oldks, ks;

        // Get the screen width and height
        public int screenH = 600, screenW = 800;

        // Graph for "pathfinding"
        public Graph gra = new Graph();
        public int graphi = 0; //it seems this is a counter set to right before the cubicle nodes are set



        // there can only be one currently selected object or employee....?!
        //.........................
        public PlaceableGameComponent CurrentSelectedObject { get; set; }

        // Currently selected employee (that we are viewing the needs of in the Needs Display)
        // NOT accessed through employeemanager - just handled by game now!
        private Employee _currentEmployee;
        public Employee CurrentEmployee 
        {
            get { return _currentEmployee; }
            set
            {
                _currentEmployee = value;
                CurrentSelectedObject = value;
            }
        }

        // Handles everything money related
        // holds cost constants, determines if player has enough funds to buy something, etc.
        public MoneyManager MoneyManager { get; set; }

        // Handles everything employee-related:
        // adding our employees (and their cubicles), resetting needs, etc.
        public EmployeeManager EmployeeManager { get; set; }

        //................................
        public ItemManager ItemManager { get; set; }

        public UI.HelpPane HelpPane; 

        public enum DisplayOrder
        {
            Background, //back-layer
            Objects,
            Menus,
            UI //front-layer
        }

        // Whether the 2D UI was clicked in the last update.  If it's true we
        // don't check for 3D object clicks
        public bool UIClicked { get; set; }
        
        /// <summary>
        /// Constructor for our Game object.
        /// </summary>
        public Game1()
        {
            Fonts = new Dictionary<string, SpriteFont>();
            graphics = new GraphicsDeviceManager(this);
            graphics.PreferredBackBufferHeight = 600;
            graphics.PreferredBackBufferWidth = 800;
            graphics.PreferMultiSampling = true;
       
            Content.RootDirectory = "Content";

            IsMouseVisible = true;

            Window.AllowUserResizing = true; // User can resize window if they want *** todo: check resize works 

            UIClicked = false;
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            //Pathfinding graph stuffs
            eff = new BasicEffect(GraphicsDevice); // access violation exceptionn unhandled
            eff.VertexColorEnabled = true;

            // Load our message configuration file (i.e. text we have the user read)
            Messages = Content.Load<Dictionary<string, string>>("Config/Messages");

            // Make a camera to hold view parameters and respond to input on update
            CurrentCam = new Camera(this);
            Components.Add(CurrentCam);

            // Draw the floor
            Components.Add(new Floor(this));
            
            // Add Clock
            time = new Clock(this);
            Components.Add(time);

            // MoneyManager needs to be created before EmployeeManager
            // (depends on existence of moneymanager for hiring funds checking)
            MoneyManager = new MoneyManager(this);
            Components.Add(MoneyManager); // need to still add this so that the sound effects load!!
            
            // Adding cubicles + employees handled by EmployeeManager
            // employeeManager has a employeemanagerpane that it adds to game components in constructor
            EmployeeManager = new EmployeeManager(this);
            Components.Add(EmployeeManager);

            // Item manager MUST come after employee manager
            // because item nodes depend on employee nodes....?
            // Add Item Manager Pane Thing
            ItemManager = new ItemManager(this);
            Components.Add(ItemManager);

            // Add Help Pane Thing
            HelpPane = new UI.HelpPane(this);
            Components.Add(HelpPane);

            // if it is here, isn't slow when starting.....****
            //InitializeWithEverything();
            
            // Add the Interface
            Components.Add(new UI.UI(this));
            
            // Create the needs display
            Components.Add(new NeedsDisplay(this));

            // Create the overlay (to be drawn last)
            Components.Add(new Overlay(this));

            base.Initialize();
        }
        
        /// <summary>
        /// Method to call to initalize the game with all employees, need objects, etc,
        /// for intermediate testing purposes.
        /// </summary>
        private void InitializeWithEverything()
        {
            // don't think this function works right?
            ItemManager.AddAllObjects();

            EmployeeManager.AddAllEmployees();

           // CurrentCam.CenterCameraOn(EmployeeManager.Employees[0].cubicle);
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            SpriteBatch = new SpriteBatch(GraphicsDevice);

            // Load the fonts to be used in the game
            Fonts.Add("needs", Content.Load<SpriteFont>("Fonts/needs"));
            Fonts.Add("status", Content.Load<SpriteFont>("Fonts/status"));
            Fonts.Add("tiny", Content.Load<SpriteFont>("Fonts/tiny"));
            Fonts.Add("info", Content.Load<SpriteFont>("Fonts/info"));
            Fonts.Add("gameTitle", Content.Load<SpriteFont>("Fonts/GameTitle"));

            // Dot Texture
            dot = Content.Load<Texture2D>("Textures/dot");
            // Splash scree and win screen
            splashScreen = Content.Load<Texture2D>("Textures/splash");
            winScreen = Content.Load<Texture2D>("Textures/win");
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering inpust, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Don't respond to input if this is not the foreground window
            if (!IsActive)
            {
                return;
            }

            // Get the screen width and height
            screenH = GraphicsDevice.Viewport.Height;
            screenW = GraphicsDevice.Viewport.Width;

            // Update mouse states
            oldms = ms;
            ms = Mouse.GetState();

            // Update keyboard states
            oldks = ks;
            ks = Keyboard.GetState();

            // *** Reference cheaty (and legit) keys: ***
            // i = item manager pane (coffee cup icon)
            // h = hire new employee pane (called from within employee manager)
            // e = employee manager pane (person icon)
            // tab = toggle between currently selected employees
            
            // P = pause/unpause
            // 1 = speed play
            // 2 = speed F
            // 3 = speed FF
            // Q or Esc = exit game
            // V
            // B
            // C
            // m = add money to current funds
            // n = remove money from current funds


            // Allows the game to exit on Windows
            // press Q key or ESC key to exit
            if (ks.IsKeyDown(Keys.Escape) || ks.IsKeyDown(Keys.Q))
            {
                this.Exit();
            }

            #region TestingKeyMaps
            //Pathfinding graph
            if ((oldks.IsKeyDown(Keys.OemQuotes)) && (ks.IsKeyUp(Keys.OemQuotes)))
            {
                pathON = !pathON;
            }
            // multiplies by 10 for some reason...
            if(ks.IsKeyDown(Keys.M)) { MoneyManager.TestingAddMoney(3000); }
          //  if(keyState.IsKeyDown(Keys.N)) MoneyManager.TestingRemoveMoney(2000);

            if(ks.IsKeyDown(Keys.X))
            {
                if (CurrentEmployee != null) CurrentEmployee.needsManager.ToggleWriteStats();
            }
            /*
            if (keyState.IsKeyDown(Keys.V))
            {
                if (CurrentEmployee != null)
                {
                    CurrentEmployee.DestNode = gra.nodes[18];
                    CurrentEmployee.path = null;
                }
            }
            if (keyState.IsKeyDown(Keys.B))
            {
                if (CurrentEmployee != null)
                {
                    CurrentEmployee.DestNode = gra.nodes[23];
                    CurrentEmployee.path = null;
                }
            }
            if (keyState.IsKeyDown(Keys.C))
            {
                if (CurrentEmployee != null)
                {
                    CurrentEmployee.DestNode = gra.nodes[2];
                    CurrentEmployee.path = null;
                }
            }
            

            
            // hack testing = g = move selected employee left
            if (keyState.IsKeyDown(Keys.G)) 
            {
                if (CurrentEmployee != null) CurrentEmployee.MoveLeft();
            }
            */
            // hack testing = h = move selected employee right

            

            
            if(oldks.IsKeyDown(Keys.D7) && ks.IsKeyUp(Keys.D7)) EmployeeManager.AddDev();
            if (oldks.IsKeyDown(Keys.D8) && ks.IsKeyUp(Keys.D8)) EmployeeManager.AddLeadDev();
            if (oldks.IsKeyDown(Keys.D9) && ks.IsKeyUp(Keys.D9)) EmployeeManager.AddSlacker();
            if (oldks.IsKeyDown(Keys.D0) && ks.IsKeyUp(Keys.D0)) EmployeeManager.AddSteve();
            
            #endregion

            if (currentGameState == GameState.Loading)
            {
                if ((oldks.IsKeyDown(Keys.Enter)) && (ks.IsKeyUp(Keys.Enter)))
                {
                    ResetGame(gameTime); 
                    currentGameState = GameState.Running;
                }
            }

            if ((currentGameState == GameState.Running))
            {
                // Check if we have reached our monetary goal
                if (MoneyManager.CheckReachedGoal())
                {
                    currentGameState = GameState.Won;
                }

                // Yayyy tab to toggle between currently selected employee is back
                if ((oldks.IsKeyDown(Keys.Tab)) && (ks.IsKeyUp(Keys.Tab)))
                {
                    EmployeeManager.NextEmployee();
                }

                // H = hire new employee pane
                if (oldks.IsKeyDown(Keys.H) && ks.IsKeyUp(Keys.H))
                {
                    EmployeeManager.newHireManagerPane.ToggleVisible();
                    //EmployeeManager.HireNew();
                }

                // E = show/hide employee manager pane
                if (oldks.IsKeyDown(Keys.E) && ks.IsKeyUp(Keys.E))
                {
                    EmployeeManager.managerPane.ToggleVisible();
                }

                // I = show/hide item manager pane
                if (oldks.IsKeyDown(Keys.I) && ks.IsKeyUp(Keys.I))
                {
                    ItemManager.managerPane.ToggleVisible();
                }

                // leave this cheat in... add all items without money deduction
                /*else if ((oldks.IsKeyDown(Keys.I)) && (ks.IsKeyUp(Keys.I)))
                {
                    ItemManager.AddAllObjects();
                }*/


                // Is there a way to lose?....
                // Perhaps by going over a certain amount of days???
                /* 
                if ((roundTimer < TimeSpan.Zero) &&
                    (retrievedFuelCells != GameConstants.NumFuelCells))
                {
                    currentGameState = GameState.Lost;
                }*/
            }

            if ((currentGameState == GameState.Won) || (currentGameState == GameState.Lost))
            {
                // Reset the world for a new game
                if ((oldks.IsKeyDown(Keys.Enter)) && (ks.IsKeyUp(Keys.Enter)))
                    ResetGame(gameTime);
            }

            // Check for clicked menu options first.
            base.Update(gameTime);

            // If no menu items were clicked, check for world items
            if (!UIClicked)
            {
                CheckMouseClick();
            }
        }

        #region picking3Dobject

        /// <summary>
        /// Check if the mouse clicked on any placeable objects in the 3D world
        /// Referenced: Selecting an Object with a Mouse (Windows)
        /// http://msdn.microsoft.com/en-us/library/bb203905(v=xnagamestudio.40
        /// </summary>
        void CheckMouseClick()
        {
            // Get the current state of the mouse
            MouseState mouseState = Mouse.GetState();

            if (mouseState.LeftButton == ButtonState.Pressed)
            {
                // Calculate a ray from the "eye" of the camera to the cursor location
                Ray pickRay = GetPickRay();
                
                PlaceableGameComponent selected = null;
                float selectedDistance = float.MaxValue;

                // Loop through each object in the scene using the Intersects method
                // to check whether the Ray intersects each object

                // alternative for cubicle picking testing//foreach(var component in Components.OfType<PlaceableGameComponent>())
                
                foreach(var component in Components.OfType<ClickableGameComponent>())
                {
                    // MSDN 3D picking online tutorial bounding sphere option
                    float? result = pickRay.Intersects(component.BoundingSphere);

                    // If the Ray intersects the model and is the closest hit
                    if (result.HasValue && result.Value < selectedDistance)
                    {
                        selected = component;
                        selectedDistance = result.Value;
                    }
                }
                
                // When you completely loop through the objects, the last object stored
                // will be the closest object underneath the area the user clicked.
                CurrentSelectedObject = selected;

                // Will be null if selected is not an Employee.
                CurrentEmployee = selected as Employee;
            }
        }


        /// <summary>
        /// Calculates a world space ray that starting at the "eye" of the camera
        /// and pointing in the direction of the cursor.
        /// Reference: CalculateCursorRay --> provided useful comments for understanding, from:
        /// http://create.msdn.com/en-US/education/catalog/sample/picking 
        /// </summary>
        /// <returns>the world space ray shooting out in the direction of the cursor</returns>
        Ray GetPickRay()
        {
            // Get the current state of the mouse
            MouseState mouseState = Mouse.GetState();

            // Get the current screen coordinates of the mouse
            int mouseX = mouseState.X;
            int mouseY = mouseState.Y;

            // ###create 2 positions in screenspace using the cursor position.
            // 0 is as close as possible to the camera, 1 is as far away as possible.###

            // Determine points in the world space on the near and far clipping panes
            Vector3 nearSource = new Vector3((float)mouseX, (float)mouseY, 0f);
            Vector3 farSource = new Vector3((float)mouseX, (float)mouseY, 1f);

            // Create a translation matrix for a point that is the origin, (0,0,0).
            Matrix world = Matrix.Identity;

            // ### use Viewport.Unproject to tell what those two screen space positions
            // would be in world space. ###

            // For the point on the near plane, pass a source vector with x and y set to the mouse position, and z set to 0.
            Vector3 nearPoint = GraphicsDevice.Viewport.Unproject(nearSource,
                CurrentCam.ProjectionMatrix, CurrentCam.ViewMatrix, world);

            // For the point on the far plane, pass a source vector with x and y set to the mouse position, and z set to 1.
            Vector3 farPoint = GraphicsDevice.Viewport.Unproject(farSource,
                CurrentCam.ProjectionMatrix, CurrentCam.ViewMatrix, world);

            // Create a Ray whose origin is at the near point and whose direction points to the far point
            // Create a ray from the near clip plane to the far clip plane.

            // ### find the direction vector that goes from the nearPoint to the farPoint
            // and normalize it....###
            Vector3 direction = farPoint - nearPoint;
            direction.Normalize();

            //### and then create a new ray using nearPoint as the source.
            return new Ray(nearPoint, direction);
        }

       



        // picking sample game from msdn rotating table
        /* private void DrawModelNames()
         {
             // begin on the spritebatch, because we're going to be drawing some text.
             SpriteBatch.Begin();

             SpriteFont font = Fonts["tiny"];

             // Calculate a ray from the "eye" of the camera to the cursor location
             Ray pickRay = GetPickRay();

             PlaceableGameComponent selected = null;
             float selectedDistance = float.MaxValue;
            
             // Loop through each object in the scene using the Intersects method
             // to check whether the Ray intersects each object
                 foreach(var component in Components.OfType<ClickableGameComponent>())
                 {
                     // MSDN 3D picking online tutorial bounding sphere option
                     float? result = pickRay.Intersects(component.BoundingSphere);

                     // If the Ray intersects the model and is the closest hit
                     if (result.HasValue && result.Value < selectedDistance)
                     {
                         selected = component;
                         selectedDistance = result.Value;
                     }
                 }

                 if (selected == null) return; 

             string modelName = selected.name;
                 // When you completely loop through the objects, the last object stored
                 // will be the closest object underneath the area the user clicked.
                // CurrentSelectedObject = selected;

                 // Will be null if selected is not an Employee.
                 //CurrentEmployee = selected as Employee;
        


             // go through all of the models...
                 // check to see if the cursorRay intersects the model....


                     // now we know that we want to draw the model's name. We want to
                     // draw the name a little bit above the model: but where's that?
                     // SpriteBatch.DrawString takes screen space coordinates, but the 
                     // model's position is stored in world space. 

                     // Use Viewport.Project to project a world space point into screen space.
             // Project the vector (0,0,0) using the model's world matrix, and the view and projection matrices.
                     // that will tell us where the model's origin is on the screen.
                   Vector3 screenSpace = graphics.GraphicsDevice.Viewport.Project(
                         Vector3.Zero, CurrentCam.ProjectionMatrix, CurrentCam.ViewMatrix, selected.ModelMatrix);

                     // we want to draw the text a little bit above that, so we'll use
                     // the screen space position - 60 to move up a little bit. A better
                     // approach would be to calculate where the top of the model is, and
                     // draw there. It's not that much harder to do, but to keep the
                     // sample easy, we'll take the easy way out.
                     Vector2 textPos = new Vector2(screenSpace.X, screenSpace.Y - 60);

                     // we want to draw the text centered around textPosition, so we'll
                     // calculate the center of the string, and use that as the origin
                     // argument to spriteBatch.DrawString. DrawString automatically
                     // centers text around the vector specified by the origin argument.

             //string text = "string to draw";
                     Vector2 stringCenter = font.MeasureString(modelName) / 2;

                     // to make the text readable, we'll draw the same thing twice, once
                     // white and once black, with a little offset to get a drop shadow
                     // effect.

                     // first we'll draw the shadow...
                     Vector2 shadowOffset = new Vector2(1, 1);
                     SpriteBatch.DrawString(font, modelName, textPos + shadowOffset, Color.Black, 0.0f, stringCenter, 1.0f, SpriteEffects.None, 0.0f);

                     // ...and then the real text on top.
                     SpriteBatch.DrawString(font, modelName, textPos, Color.White, 0.0f, stringCenter, 1.0f, SpriteEffects.None, 0.0f);
                
            

             SpriteBatch.End();
         }*/

        #endregion

        /// <summary>
        /// 
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="w"></param>
        /// <param name="h"></param>
        /// <param name="t"></param>
        /// <param name="font"></param>
        public void drawFrame(int x, int y, int w, int h, string title, SpriteFont font)
        {
            // Draw the frame that goes around the management panes and item listings.
            Rectangle titleBar = new Rectangle(x, y, w, 20);
            Rectangle box = new Rectangle(x, y, w, h);
            Rectangle border = new Rectangle(x - 3, y - 3, w + 6, h + 6);

            SpriteBatch.Draw(dot, border, UIblue);
            SpriteBatch.Draw(dot, box, Color.White);
            SpriteBatch.Draw(dot, titleBar, UIblue);
            SpriteBatch.DrawString(font, title, new Vector2(x + 5, y), Color.White);
        }
        #region pathfinding

        BasicEffect eff;
        public bool pathON = false;
        //Draw Graph (test for pathfinding)
        public void drawGraph(Matrix ModelMatrix, ICamera camera)
        {
            if (pathON)
            {
                eff.Projection = camera.ProjectionMatrix;
                //eff.World = ModelMatrix;
                eff.View = camera.ViewMatrix;

                VertexPositionColor[] vertices = new VertexPositionColor[gra.edges.Count * 2];
                int eCount = 0;

                foreach (Edge e in gra.edges)
                {
                    vertices[eCount * 2].Position = e.n1.pos;
                    vertices[eCount * 2].Color = Color.Red;
                    vertices[(eCount * 2) + 1].Position = e.n2.pos;
                    vertices[(eCount * 2) + 1].Color = Color.Red;
                    //DrawLine(dot, new Vector2(e.n1.pos.X * 4 + 200, e.n1.pos.Z * 4 + 400), new Vector2(e.n2.pos.X * 4 + 200, e.n2.pos.Z * 4 + 400), Color.Yellow);
                    eCount++;
                }
                eff.CurrentTechnique.Passes[0].Apply();
                graphics.GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.LineList, vertices, 0, gra.edges.Count);

                SpriteBatch.Begin();
                foreach (Node n in gra.nodes)
                {
                    Vector3 projectedPosition = GraphicsDevice.Viewport.Project(n.pos, eff.Projection, eff.View, Matrix.Identity);
                    Vector2 screenPosition = new Vector2(projectedPosition.X, projectedPosition.Y);
                    SpriteBatch.DrawString(Fonts["info"], n.ToString(), screenPosition, Color.Yellow);
                }
                SpriteBatch.End();
            }
        }
        #endregion
        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            switch (currentGameState) // todo: is something in here making starting the game slow?!?!?***
            {
                case GameState.Loading:
                    DrawSplashScreen();
                    return; //break;
                case GameState.Running:
                    //DrawModelNames(); 
                    //DrawGameplayScreen();
                    break;
                case GameState.Won:
                    DrawWinOrLossScreen(true);
                    return; // was break;
                case GameState.Lost: // this never happens
                    //DrawWinOrLossScreen(false);
                    break;
            };

            // Draw the 3-D game components
            base.Draw(gameTime);
        }


        // game state stubs reference fuelcell game
        #region GameStateFunctions

        private void DrawSplashScreen()
        {
            graphics.GraphicsDevice.Clear(Color.SteelBlue);
            
            SpriteBatch.Begin();

            // Pretty splash screen that Yee made. well, everything she makes is pretty.
            SpriteBatch.Draw(splashScreen, new Vector2(0, 0), Color.White);
            //Draw the title
            SpriteBatch.DrawString(Fonts["gameTitle"], Messages["NameOfTheGame"], new Vector2(80, 75), Color.White);

            float yoff = -130f;
            drawInstructionString("Welcome", ref yoff, UIblue);
            drawInstructionString("Instructions1", ref yoff, UIblue);
            drawInstructionString("Instructions2", ref yoff, UIblue);
            drawInstructionString("Instructions3", ref yoff, UIblue);
            drawInstructionString("Instructions4", ref yoff, UIblue);
            SpriteBatch.End();

            //re-enable depth buffer after sprite batch disablement

            //GraphicsDevice.DepthStencilState.DepthBufferEnable = true;
            DepthStencilState dss = new DepthStencilState();
            dss.DepthBufferEnable = true;
            GraphicsDevice.DepthStencilState = dss;
        }

        /// <summary>
        /// Draw one instruction message on the splash screen
        /// </summary>
        /// <param name="messageName">Name of the message in our resource file</param>
        /// <param name="lineOff">Position relative to center of screen to draw text</param>
        /// <param name="color">Color to draw with</param>
        private void drawInstructionString(string messageName, ref float lineOff, Color color)
        {
            var font = Fonts["needs"];
            var message = Messages[messageName];
            
            Vector2 size = font.MeasureString(message);
            Vector2 center = size / 2f;

            //float xOff = (GraphicsDevice.Viewport.Width / 2.0f - center.X);
            //Yee doesn't like it centered
            float xOff = 90.0f;
            float yOff = lineOff + GraphicsDevice.Viewport.Height / 2 - center.Y;

            lineOff += size.Y - 10.0f ;
            
            var strPosition = new Vector2(xOff, yOff);
            SpriteBatch.DrawString(font, message, strPosition, color);
        }

        private void DrawWinOrLossScreen(bool result) // true if won, false if not
        {
            SpriteFont font = Fonts["needs"]; // another variable just to make code shorter

            string gameResult = "";
            if (result) gameResult = "Thanks for playing :)";
            else gameResult = "You Lose :("; // pretty sure this never happens, as the game is now...

            string playAgain = "Play Again? (press enter) ";

            // GraphicsDevice.Viewport.Width and .Height... just to shorten it
            float gdvW = GraphicsDevice.Viewport.Width;
            float gdvH = GraphicsDevice.Viewport.Height;

            // amounts to offset the text by
            float xOff, yOff;
            xOff = yOff = 0f;

            //Vector2 viewportSize = new Vector2(gdvW,gdvH);
            Vector2 strCenter;
            
            Vector2 strResult = font.MeasureString(gameResult);
            Vector2 strPlayAgainSize = font.MeasureString(playAgain); 
            Vector2 strPosition;
            strCenter = new Vector2(strResult.X / 2, strResult.Y / 2);

            //yOff = (gdvH / 2 - strCenter.Y);
            yOff = screenH - 100;
            xOff = (gdvW / 2 - strCenter.X);
            strPosition = new Vector2((int)xOff, (int)yOff);

            SpriteBatch.Begin();

            // Pretty splash screen that Yee made. well, everything she makes is pretty.
            SpriteBatch.Draw(winScreen, new Vector2(0, 0), Color.White);

            SpriteBatch.DrawString(font, gameResult, strPosition, UIblue);

            strCenter = new Vector2(strPlayAgainSize.X / 2, strPlayAgainSize.Y / 2);
            yOff = (gdvH / 2 - strCenter.Y) + (float)font.LineSpacing;
            xOff = (gdvW / 2 - strCenter.X);
            strPosition = new Vector2((int)xOff, (int)yOff);

           // SpriteBatch.DrawString(font, playAgain, strPosition, Color.AntiqueWhite);

            SpriteBatch.End();

            //re-enable depth buffer after sprite batch disablement

            //GraphicsDevice.DepthStencilState.DepthBufferEnable = true;
            DepthStencilState dss = new DepthStencilState();
            dss.DepthBufferEnable = true;
            GraphicsDevice.DepthStencilState = dss;
             
        }

        // TODO: FIX RESET! all reset functions for new game
        private void ResetGame(GameTime gameTime) //, float aspectRatio)
        {
            
            // Add a new Clock
            Components.Remove(time);
            time = new Clock(this);
            Components.Add(time);

            // Keep same camera, keep floor, keep UI, keep graph...

            MoneyManager.Reset();
            EmployeeManager.Reset();
            ItemManager.Reset();
            /*
            foreach (var comp in Components.OfType<ClickableGameComponent>()) // invalid operation exception unhandled
            {
                Components.Remove(comp);
            }*/

            time.Reset();

            currentGameState = GameState.Running;
        }

        #endregion

    }
}
